home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / drivers2.zip / NI6510.ASM < prev    next >
Assembly Source File  |  1992-01-23  |  21KB  |  900 lines

  1. version    equ    1
  2.  
  3. ; Copyright, 1990-1992, Russell Nelson, Crynwr Software
  4.  
  5. ;   This program is free software; you can redistribute it and/or modify
  6. ;   it under the terms of the GNU General Public License as published by
  7. ;   the Free Software Foundation, version 1.
  8. ;
  9. ;   This program is distributed in the hope that it will be useful,
  10. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ;   GNU General Public License for more details.
  13. ;
  14. ;   You should have received a copy of the GNU General Public License
  15. ;   along with this program; if not, write to the Free Software
  16. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. comment /
  19.  
  20. I found a problem when using the Interlan NI6510 Packet Driver with 16 bit DMA.
  21. I looked at the source and I think I found the bug.  I've tested the fixed code
  22. and it seems to work fine for all possible DMA settings, at least over here.
  23.  
  24. Anto Prijosoesilo,
  25. Network & Microcomputer Consultant,
  26. University of North Texas Computing Center,
  27. Denton, Texas
  28.  
  29. /
  30.  
  31.     .286                ;the 6510 requires a 286.
  32.  
  33.     include    defs.asm
  34.  
  35. DATA_REG    equ    0
  36. ADDR_REG    equ    2
  37.     CSR0        equ    0
  38.     CSR1        equ    1
  39.     CSR2        equ    2
  40.     CSR3        equ    3
  41. RESET        equ    4
  42. CONFIG        equ    5
  43. EBASE        equ    8
  44.  
  45. DMA_8MASK_REG    equ    0Ah
  46. DMA_16MASK_REG    equ    0D4h
  47.  
  48. DMA_8MODE_REG    equ    0Bh
  49. DMA_16MODE_REG    equ    0D6h
  50.  
  51. CASCADE_MODE      equ    0C0h
  52. SET_DMA_MASK      equ    4
  53. DMA_CHANNEL_FIELD equ    3
  54.  
  55.  
  56. outport    macro    reg
  57.     push    ax
  58.     setport    ADDR_REG
  59.     mov    ax,reg
  60.     out    dx,ax
  61.     in    ax,dx            ;always follow a write by a read
  62.  
  63.     setport    DATA_REG
  64.     pop    ax
  65.     out    dx,ax
  66.     in    ax,dx            ;always follow a write by a read
  67.  
  68.     endm
  69.  
  70.  
  71. ;
  72. ;     Control and Status Register 0 (CSR0) bit definitions
  73. ;
  74. CSR0_ERR    equ     8000h    ; Error summary
  75. CSR0_BABL    equ     4000h    ; Babble transmitter timeout error
  76. CSR0_CERR    equ    2000h    ; Collision Error
  77. CSR0_MISS    equ    1000h    ; Missed packet
  78. CSR0_MERR    equ    0800h    ; Memory Error
  79. CSR0_RINT    equ    0400h    ; Reciever Interrupt
  80. CSR0_TINT       equ    0200h    ; Transmit Interrupt
  81. CSR0_IDON    equ    0100h    ; Initialization Done
  82. CSR0_INTR    equ    0080h    ; Interrupt Flag
  83. CSR0_INEA    equ    0040h    ; Interrupt Enable
  84. CSR0_RXON    equ    0020h    ; Receiver on
  85. CSR0_TXON    equ    0010h   ; Transmitter on
  86. CSR0_TDMD    equ    0008h    ; Transmit Demand
  87. CSR0_STOP    equ    0004h     ; Stop
  88. CSR0_STRT    equ    0002h    ; Start
  89. CSR0_INIT    equ    0001h    ; Initialize
  90.  
  91. ;
  92. ;     Initialization Block  Mode operation Bit Definitions.
  93. ;
  94. M_PROM        equ    8000h    ; Promiscuous Mode
  95. M_INTL        equ    0040h   ; Internal Loopback
  96. M_DRTY        equ    0020h   ; Disable Retry
  97. M_COLL        equ    0010h    ; Force Collision
  98. M_DTCR        equ    0008h    ; Disable Transmit CRC)
  99. M_LOOP        equ    0004h    ; Loopback
  100. M_DTX        equ    0002h    ; Disable the Transmitter
  101. M_DRX        equ    0001h   ; Disable the Reciever
  102.  
  103.  
  104. ;
  105. ;     Receive message descriptor bit definitions.
  106. ;
  107. RCV_OWN        equ    8000h    ; owner bit 0 = host, 1 = lance
  108. RCV_ERR        equ    4000h    ; Error Summary
  109. RCV_FRAM    equ     2000h    ; Framing Error
  110. RCV_OFLO    equ    1000h    ; Overflow Error
  111. RCV_CRC        equ    0800h    ; CRC Error
  112. RCV_BUF_ERR    equ     0400h    ; Buffer Error
  113. RCV_START    equ    0200h    ; Start of Packet
  114. RCV_END        equ    0100h    ; End of Packet
  115.  
  116.  
  117. ;
  118. ;    Transmit  message descriptor bit definitions.
  119. ;
  120. XMIT_OWN    equ    8000h    ; owner bit 0 = host, 1 = lance
  121. XMIT_ERR    equ    4000h   ; Error Summary
  122. XMIT_RETRY    equ    1000h   ; more the 1 retry needed to Xmit
  123. XMIT_1_RETRY    equ    0800h    ; one retry needed to Xmit
  124. XMIT_DEF    equ    0400h    ; Deferred
  125. XMIT_START    equ    0200h    ; Start of Packet
  126. XMIT_END    equ    0100h    ; End of Packet
  127.  
  128. ;
  129. ;    Miscellaneous Equates
  130. ;
  131.  
  132. TRANSMIT_BUF_COUNT    equ    1
  133. RECEIVE_BUF_COUNT    equ    8
  134. TRANSMIT_BUF_SIZE    equ    1518
  135. RECEIVE_BUF_SIZE    equ    1518
  136.  
  137. ;
  138. ;    Receive Message Descriptor
  139. ;
  140. rcv_msg_dscp struc
  141.     rmd0    dw    ?    ; Rec. Buffer Lo-Address
  142.     rmd1    dw    ?    ; Status bits / Hi-Address
  143.     rmd2    dw    ?    ; Buff Byte-length (2's Comp)
  144.     rmd3    dw    ?    ; Receive message length
  145. rcv_msg_dscp ends
  146.  
  147.  
  148. ;
  149. ;    Transmit Message Descriptor
  150. ;
  151. xmit_msg_dscp struc
  152.     tmd0    dw    ?    ; Xmit Buffer Lo-Address
  153.     tmd1    dw    ?    ; Status bits / Hi-Address
  154.     tmd2     dw    ?    ; Buff Byte-length (2's Comp)
  155.     tmd3    dw    ?    ; Buffer Status bits & TDR value
  156. xmit_msg_dscp ends
  157.  
  158. code    segment    para public
  159.     assume    cs:code, ds:code
  160.  
  161.     public    int_no
  162. int_no    db    2,0,0,0            ;must be four bytes long for get_number.
  163. io_addr    dw    -1,-1
  164. dma_no    db    ?
  165.  
  166.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  167. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  168. driver_type    db    35        ;from the packet spec
  169. driver_name    db    'NI6510',0    ;name of the driver.
  170. driver_function    db    2        ;basic, extended
  171. parameter_list    label    byte
  172.     db    1    ;major rev of packet driver
  173.     db    9    ;minor rev of packet driver
  174.     db    14    ;length of parameter list
  175.     db    EADDR_LEN    ;length of MAC-layer address
  176.     dw    GIANT    ;MTU, including MAC headers
  177.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  178.     dw    RECEIVE_BUF_COUNT-1    ;(# of back-to-back MTU rcvs) - 1
  179.     dw    TRANSMIT_BUF_COUNT-1    ;(# of successive xmits) - 1
  180. int_num    dw    0    ;Interrupt # to hook for post-EOI
  181.             ;processing, 0 == none,
  182.  
  183.     public    rcv_modes
  184. rcv_modes    dw    7        ;number of receive modes in our table.
  185.         dw    0               ;There is no mode zero
  186.         dw    rcv_mode_1
  187.         dw    0        ;only ours.
  188.         dw    rcv_mode_3    ;ours plus broadcast
  189.         dw    0        ;some multicasts
  190.         dw    rcv_mode_5    ;all multicasts
  191.         dw    rcv_mode_6    ;all packets
  192.  
  193. ;
  194. ;the LANCE requires that the descriptor pointers be on a qword boundary.
  195. ;
  196.     align    8
  197.  
  198. transmit_dscps    xmit_msg_dscp    TRANSMIT_BUF_COUNT dup(<>)
  199. receive_dscps    rcv_msg_dscp    RECEIVE_BUF_COUNT dup(<>)
  200.  
  201. transmit_head    dw    transmit_dscps    ;->next packet to be filled by host.
  202. receive_head    dw    receive_dscps    ;->next packet to be filled by LANCE.
  203.  
  204. ;
  205. ;      LANCE Initialization Block
  206. ;
  207.     align    2
  208. init_block        label    byte
  209. init_mode        dw    0
  210. init_addr        db    EADDR_LEN dup(?)    ; Our Ethernet address
  211. init_filter        db    8 dup(0)    ;Multicast filter.
  212. init_receive        dw    ?,?        ;Receive Ring Pointer.
  213. init_transmit          dw    ?,?          ;Transmit Ring Pointer.
  214.  
  215.     public    as_send_pkt
  216. ; The Asynchronous Transmit Packet routine.
  217. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  218. ;   interrupts possibly enabled.
  219. ; Exit with nc if ok, or else cy if error, dh set to error number.
  220. ;   es:di and interrupt enable flag preserved on exit.
  221. as_send_pkt:
  222.     ret
  223.  
  224.     public    drop_pkt
  225. ; Drop a packet from the queue.
  226. ; Enter with es:di -> iocb.
  227. drop_pkt:
  228.     assume    ds:nothing
  229.     ret
  230.  
  231.     public    xmit
  232. ; Process a transmit interrupt with the least possible latency to achieve
  233. ;   back-to-back packet transmissions.
  234. ; May only use ax and dx.
  235. xmit:
  236.     assume    ds:nothing
  237.     ret
  238.  
  239.  
  240.     public    send_pkt
  241. send_pkt:
  242. ;enter with ds:si -> packet, cx = packet length.
  243. ;exit with nc if ok, or else cy if error, dh set to error number.
  244.     assume    ds:nothing
  245.  
  246.     xor    bx,bx
  247.  
  248.     mov    ax,18
  249.     call    set_timeout
  250. send_pkt_1:
  251.     test    transmit_dscps[bx].tmd1,XMIT_OWN    ;Did the lance chip give it back?
  252.     je    send_pkt_2
  253.     call    do_timeout
  254.     jne    send_pkt_1
  255.     mov    dh,CANT_SEND
  256.     stc
  257.     ret
  258. send_pkt_2:
  259. ;reset error indications.
  260.     and    transmit_dscps[bx].tmd1,not (XMIT_ERR or XMIT_DEF or XMIT_1_RETRY or XMIT_RETRY)    ;Did the lance chip give it back?
  261.     mov    transmit_dscps[bx].tmd3,0    ;reset all error bits.
  262.  
  263.     mov    ax,cx            ;store the count.
  264.     cmp    ax,RUNT            ; minimum length for Ether
  265.     ja    oklen
  266.     mov    ax,RUNT            ; make sure size at least RUNT
  267. oklen:
  268.     neg    ax
  269.     mov    transmit_dscps[bx].tmd2,ax
  270.  
  271.     mov    ax,transmit_dscps[bx].tmd0    ;store the packet.
  272.     mov    dx,transmit_dscps[bx].tmd1
  273.     call    phys_to_segmoffs
  274.     rep    movsb
  275.  
  276.     or    transmit_dscps[bx].tmd1,XMIT_OWN    ;give it to the lance chip.
  277.  
  278. ;Inform LANCE that it should poll for a packet.
  279.     loadport
  280.     mov    ax,CSR0_INEA or CSR0_TDMD
  281.     outport    CSR0
  282.     clc
  283.     ret
  284.  
  285.  
  286.     public    get_address
  287. get_address:
  288. ;get the address of the interface.
  289. ;enter with es:di -> place to get the address, cx = size of address buffer.
  290. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  291.     assume    ds:code
  292.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  293.     jb    get_address_2
  294.     mov    cx,EADDR_LEN
  295.     loadport            ; Get our Ethernet address base.
  296.     setport    EBASE
  297.     cld
  298. get_address_1:
  299.     insb                ; get a byte of the eprom address
  300.     inc    dx            ; next register
  301.     loop    get_address_1        ; go back for rest
  302.     mov    cx,EADDR_LEN
  303.     clc
  304.     ret
  305. get_address_2:
  306.     stc
  307.     ret
  308.  
  309.  
  310.     public    set_address
  311. set_address:
  312. ;enter with ds:si -> Ethernet address, CX = length of address.
  313. ;exit with nc if okay, or cy, dh=error if any errors.
  314.     assume    ds:nothing
  315.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  316.     je    set_address_4
  317.     mov    dh,BAD_ADDRESS
  318.     stc
  319.     jmp    short set_address_done
  320. set_address_4:
  321.  
  322.     push    cs
  323.     pop    es
  324.     mov    di,offset init_addr
  325.     rep    movsb
  326.     call    initialize        ;initialize with our new address.
  327.  
  328. set_address_okay:
  329.     mov    cx,EADDR_LEN        ;return their address length.
  330.     clc
  331. set_address_done:
  332.     push    cs
  333.     pop    ds
  334.     assume    ds:code
  335.     ret
  336.  
  337.  
  338. rcv_mode_1:
  339.     mov    ax,M_DRX or M_DTX    ;disable the receiver and transmitter.
  340.     jmp    initialize_nomulti
  341. rcv_mode_3:
  342.     xor    ax,ax            ;don't accept any multicast frames.
  343.     call    initialize_multi
  344.     mov    ax,0            ;non-promiscuous mode
  345.     jmp    short initialize_nomulti
  346. rcv_mode_5:
  347.     mov    ax,-1            ;accept any multicast frames.
  348.     call    initialize_multi
  349.     mov    ax,0            ;non-promiscuous mode
  350.     jmp    short initialize_nomulti
  351. rcv_mode_6:
  352.     mov    ax,M_PROM    ;promiscuous mode
  353. initialize_nomulti:
  354. initialize:
  355.     mov    init_mode,ax
  356.     loadport
  357.     mov    ax,CSR0_STOP        ;reset the INIT bit.
  358.     outport    CSR0
  359.  
  360.     mov    ax,CSR0_INEA or CSR0_STRT or CSR0_INIT    ;reinit and restart.
  361.     outport    CSR0
  362.  
  363.     setport    DATA_REG
  364.  
  365.     mov    ax,36            ;wait one second for the board
  366.     call    set_timeout        ;  to timeout.
  367. initialize_1:
  368.     in    ax,dx
  369.     test    ax,CSR0_IDON
  370.     jne    initialize_2
  371.     call    do_timeout
  372.     jne    initialize_1
  373.     stc
  374.     ret
  375. initialize_2:
  376.     clc
  377.     ret
  378.  
  379.  
  380. initialize_multi:
  381. ;enter with ax = value for all multicast hash bits.
  382.     push    cs
  383.     pop    es
  384.     mov    di,offset init_filter
  385.     mov    cx,8/2
  386.     rep    stosw
  387.     ret
  388.  
  389.  
  390.     public    set_multicast_list
  391. set_multicast_list:
  392. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  393. ;return nc if we set all of them, or cy,dh=error if we didn't.
  394.     mov    dh,NO_MULTICAST        ;for some reason we can't do multi's.
  395.     stc
  396.     ret
  397.  
  398.  
  399.     public    terminate
  400. terminate:
  401.     call    rcv_mode_1        ;don't receive any apckets.
  402.  
  403. ;This routine will remove the (host) DMA controller from
  404. ;cascade mode of operation.
  405.     mov    al,dma_no
  406.     or    al,SET_DMA_MASK
  407.     cmp    dma_no,4        ;If channel 5 or 6,
  408.     ja    terminate_16        ;  use sixteen bit dma.
  409. terminate_8:
  410.     out    DMA_8MASK_REG,al
  411.     jmp    short terminate_done
  412. terminate_16:
  413.     out    DMA_16MASK_REG,al
  414. terminate_done:
  415.     ret
  416.  
  417.     public    reset_interface
  418. reset_interface:
  419. ;reset the interface.
  420.     assume    ds:code
  421.     ret
  422.  
  423.  
  424. ;called when we want to determine what to do with a received packet.
  425. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  426.     extrn    recv_find: near
  427.  
  428. ;called after we have copied the packet into the buffer.
  429. ;enter with ds:si ->the packet, cx = length of the packet.
  430.     extrn    recv_copy: near
  431.  
  432.     extrn    count_in_err: near
  433.     extrn    count_out_err: near
  434.  
  435. LANCE_ISR_ACKNOWLEDGE equ (CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  436.  
  437.     public    recv
  438. recv:
  439. ;called from the recv isr.  All registers have been saved, and ds=cs.
  440. ;Upon exit, the interrupt will be acknowledged.
  441.     assume    ds:code
  442.  
  443.     loadport
  444.     setport    ADDR_REG
  445.     mov    ax,CSR0
  446.     out    dx,ax
  447.     in    ax,dx
  448.     setport    DATA_REG
  449.     in    ax,dx
  450.     mov    bx,ax            ;make a copy.
  451.  
  452. ; Acknowledge the Interrupt from the controller, but disable further
  453. ; controller Interrupts until we service the current interrupt.
  454. ;
  455. ;(CSR0_INEA or CSR0_TDMD or CSR0_STOP or CSR0_STRT or CSR0_INIT)
  456. ;
  457.     and    ax,not LANCE_ISR_ACKNOWLEDGE
  458.     out    dx,ax
  459.     in    ax,dx        ; follow all writes by a read
  460.  
  461.     test    bx,CSR0_RINT        ;receive interrupt?
  462.     je    recv_done        ;no, we're done.
  463.  
  464.     mov    bx,receive_head
  465.  
  466. recv_search:
  467.     test    code:[bx].rmd1,RCV_OWN    ;do we own this buffer?
  468.     je    recv_own        ;yes - process it.
  469.     call    inc_recv_ring        ;go to the next one.
  470.     cmp    bx,receive_head        ;did we get back to the beginning?
  471.     jne    recv_search        ;not yet.
  472.     jmp    short recv_done        ;yes -- spurious interrupt!
  473. recv_own:
  474.     test    code:[bx].rmd1,RCV_ERR    ;Any errors in this buffer?
  475.     jne    recv_err        ;yes -- ignore this packet.
  476.  
  477.     mov    ax,code:[bx].rmd0    ;fetch the packet.
  478.     mov    dx,code:[bx].rmd1
  479.     call    phys_to_segmoffs
  480.  
  481.     push    es
  482.     push    di
  483.     push    bx
  484.  
  485.     mov    cx,code:[bx].rmd3
  486.     and    cx,0fffh        ;strip off the reserved bits
  487.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  488.                     ;  point to the packet type.
  489.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  490.     mov    ax, es:[di]
  491.     xchg    ah, al
  492.     cmp     ax, 1500
  493.     ja    BlueBookPacket
  494.     inc    di            ;set di to 802.2 header
  495.     inc    di
  496.     mov    dl, IEEE8023
  497. BlueBookPacket:
  498.     push    cx
  499.     call    recv_find
  500.     pop    cx
  501.  
  502.     pop    bx
  503.     pop    si
  504.     pop    ds
  505.     assume    ds:nothing
  506.  
  507.     mov    ax,es            ;is this pointer null?
  508.     or    ax,di
  509.     je    recv_free        ;yes - just free the frame.
  510.  
  511.     push    es
  512.     push    di
  513.     push    cx
  514.     rep    movsb
  515.     pop    cx
  516.     pop    si
  517.     pop    ds
  518.     assume    ds:nothing
  519.  
  520.     call    recv_copy
  521.  
  522.     jmp    short recv_free
  523.  
  524. recv_err:
  525.     call    count_in_err
  526. recv_free:
  527.     push    cs
  528.     pop    ds
  529.     assume    ds:code
  530.  
  531. ;clear any error bits.
  532.     and    code:[bx].rmd1,not (RCV_ERR or RCV_FRAM or RCV_OFLO or RCV_CRC or RCV_BUF_ERR)
  533.     or    code:[bx].rmd1,RCV_OWN    ;give it back to the lance.
  534.     call    inc_recv_ring        ;go to the next one.
  535.     test    code:[bx].rmd1,RCV_OWN    ;Do we own this one?
  536.     je    recv_own
  537.     mov    receive_head,bx        ;remember where the next one starts.
  538. recv_done:
  539.     loadport            ;enable interrupts again.
  540.     setport    DATA_REG
  541.     mov    ax,CSR0_INEA
  542.     out    dx,ax
  543.     ret
  544.  
  545.  
  546. inc_recv_ring:
  547. ;advance bx to the next receive ring descriptor.
  548.     assume    ds:nothing
  549.     add    bx,(size rcv_msg_dscp)
  550.     cmp    bx,offset receive_dscps + RECEIVE_BUF_COUNT * (size rcv_msg_dscp)
  551.     jb    inc_recv_ring_1
  552.     mov    bx,offset receive_dscps
  553. inc_recv_ring_1:
  554.     ret
  555.  
  556.  
  557.     public    recv_exiting
  558. recv_exiting:
  559. ;called from the recv isr after interrupts have been acknowledged.
  560. ;Only ds and ax have been saved.
  561.     assume    ds:nothing
  562.     ret
  563.  
  564.  
  565. phys_to_segmoffs:
  566. ;enter with dx:ax as the physical address of the buffer,
  567. ;exit with es:di -> buffer.
  568.     shl    dx,16-4            ;move the upper four bits into position.
  569.     mov    di,ax            ;now get the low 12 bits of the segment.
  570.     shr    di,4
  571.     or    dx,di            ;combine them.
  572.     mov    es,dx
  573.     mov    di,ax
  574.     and    di,0fh            ;now compute the offset.
  575.     ret
  576.  
  577.     include    timeout.asm
  578.  
  579. ;we use this memory for buffers once we've gone resident.
  580. transmit_bufs    equ    $
  581. receive_bufs    equ    transmit_bufs + TRANSMIT_BUF_COUNT * TRANSMIT_BUF_SIZE
  582. end_resident    equ    receive_bufs + RECEIVE_BUF_COUNT * RECEIVE_BUF_SIZE
  583.  
  584.     public    usage_msg
  585. usage_msg    db    "usage: ni6510 [-n] [-d] [-w] <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  586. no_board_msg    db    "No NI6510 detected.",CR,LF,'$'
  587. io_addr_funny_msg    label    byte
  588.         db    "No NI6510 detected, continuing anyway.",CR,LF,'$'
  589. bad_reset_msg    db    "Unable to reset the NI6510.",CR,LF,'$'
  590. bad_init_msg    db    "Unable to initialize the NI6510.",CR,LF,'$'
  591.  
  592.     public    copyright_msg
  593. copyright_msg    db    "Packet driver for a Racal Interlan NI6510, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  594.         db    '$'
  595.  
  596. int_nos        db    9, 12, 15, 5    ;interrupt numbers.
  597. dma_nos        db    0, 3, 5, 6    ;dma channel numbers
  598.  
  599. int_no_name    db    "Interrupt number ",'$'
  600. io_addr_name    db    "I/O port ",'$'
  601.  
  602.     extrn    set_recv_isr: near
  603.     extrn    maskint: near
  604.  
  605. ;enter with si -> argument string, di -> dword to store.
  606. ;if there is no number, don't change the number.
  607.     extrn    get_number: near
  608.  
  609. ;enter with dx -> name of word, di -> dword to print.
  610.     extrn    print_number: near
  611.  
  612.     public    parse_args
  613. parse_args:
  614. ;exit with nc if all went well, cy otherwise.
  615.     assume    ds:code
  616.     mov    di,offset int_no
  617.     call    get_number
  618.     mov    di,offset io_addr
  619.     call    get_number
  620.     clc
  621.     ret
  622.  
  623.  
  624.     public    etopen
  625. etopen:
  626.     assume    ds:code
  627.  
  628.     cmp    io_addr,-1        ;Did they ask for auto-detect?
  629.     je    find_board
  630.  
  631.     call    detect_board        ;no, just verify its existance.
  632.     je    find_board_found
  633.  
  634.     mov    dx,offset io_addr_funny_msg
  635.     mov    ah,9
  636.     int    21h
  637.  
  638.     jmp    find_board_found
  639.  
  640. find_board:
  641.     mov    io_addr,300h        ;Search for the Ethernet address.
  642.     mov    io_addr+2,0
  643. find_board_0:
  644.     call    detect_board
  645.     je    find_board_found
  646. find_board_again:
  647.     add    io_addr,20h        ;not at this port, try another.
  648.     cmp    io_addr,360h
  649.     jbe    find_board_0
  650.  
  651.     mov    dx,offset no_board_msg    ;Tell them that we can't find it.
  652.     mov    ah,9
  653.     int    21h
  654.  
  655.     stc
  656.     ret
  657. find_board_found:
  658.  
  659.     loadport            ;get the configuration register and
  660.     setport    CONFIG            ;  determine the interrupt number.
  661.     in    al,dx
  662.     shr    al,2
  663.     and    al,3
  664.     mov    bl,al
  665.     xor    bh,bh
  666.     mov    al,int_nos[bx]
  667.     mov    int_no,al
  668.  
  669. ;This routine will put the (host) DMA controller into
  670. ;cascade mode of operation.
  671.  
  672.     in    al,dx            ;get the dma channel field.
  673.     and    al,3
  674.     mov    bl,al
  675.     xor    bh,bh
  676.     mov    al,dma_nos[bx]
  677.     mov    dma_no,al
  678.     mov    ah,al            ;save a copy.
  679.     and    al,DMA_CHANNEL_FIELD
  680.     or    al,SET_DMA_MASK
  681.     cmp    ah,4            ;If channel 5 or 6,
  682.     ja    dma_16            ;  use sixteen bit dma.
  683. dma_8:
  684.     out    DMA_8MASK_REG,al
  685.     mov    al,ah
  686.     or    al,CASCADE_MODE
  687.     out    DMA_8MODE_REG,al
  688.     mov    al,ah
  689.     out    DMA_8MASK_REG,al
  690.     jmp    short dma_done
  691. dma_16:
  692.     out    DMA_16MASK_REG,al
  693.     and    ah,DMA_CHANNEL_FIELD
  694.     mov    al,ah
  695.     or    al,CASCADE_MODE
  696.     out    DMA_16MODE_REG,al
  697.     mov    al,ah
  698.     out    DMA_16MASK_REG,al
  699. dma_done:
  700.  
  701.     mov    al, int_no        ; Get board's interrupt vector
  702.     add    al, 8
  703.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  704.     jb    set_int_num        ; No.
  705.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  706. set_int_num:
  707.     xor    ah, ah            ; Clear high byte
  708.     mov    int_num, ax        ; Set parameter_list int num.
  709.  
  710.     mov    al,int_no
  711.     call    maskint            ;disable these interrupts.
  712.  
  713.     loadport
  714.     setport    RESET
  715.     out    dx,al
  716.  
  717.     setport    CSR0
  718.     in    ax,dx
  719.     cmp    ax,CSR0_STOP
  720.     je    reset_ok
  721.  
  722.     mov    dx,offset bad_reset_msg
  723.     mov    ah,9
  724.     int    21h
  725.  
  726.     stc
  727.     ret
  728. reset_ok:
  729.  
  730. ;set up transmit descriptor ring.
  731.     push    ds
  732.     pop    es
  733.     mov    cx,TRANSMIT_BUF_COUNT
  734.     mov    bx,offset transmit_dscps
  735.     mov    di,offset transmit_bufs
  736. setup_transmit:
  737.     call    segmoffs_to_phys
  738.  
  739.     or    dx,XMIT_START or XMIT_END
  740.     mov    [bx].tmd0,ax        ;points to the buffer.
  741.     mov    [bx].tmd1,dx
  742.  
  743.     add    bx,(size xmit_msg_dscp)
  744.     add    di,TRANSMIT_BUF_SIZE
  745.     loop    setup_transmit
  746.  
  747. ;set up receive descriptor ring.
  748.     mov    cx,RECEIVE_BUF_COUNT
  749.     mov    bx,offset receive_dscps
  750.     mov    di,offset receive_bufs
  751. setup_receive:
  752.     call    segmoffs_to_phys
  753.  
  754.     or    dx,RCV_OWN
  755.     mov    [bx].rmd0,ax        ;points to the buffer.
  756.     mov    [bx].rmd1,dx
  757.  
  758.     mov    [bx].rmd2,-RECEIVE_BUF_SIZE
  759.     mov    [bx].rmd3,0
  760.  
  761.   if 0
  762.     push    di            ;initialize the buffers to 55aa.
  763.     push    cx
  764.     mov    cx,RECEIVE_BUF_SIZE/2
  765.     mov    ax,55aah
  766.     rep    stosw
  767.     pop    cx
  768.     pop    di
  769.   endif
  770.  
  771.     add    bx,(size rcv_msg_dscp)
  772.     add    di,RECEIVE_BUF_SIZE
  773.     loop    setup_receive
  774.  
  775. ;initialize the board.
  776.     mov    cx,EADDR_LEN        ;get our address.
  777.     mov    di,offset init_addr
  778.     call    get_address
  779.  
  780.     mov    cx,RECEIVE_BUF_COUNT
  781.     call    compute_log2
  782.  
  783.     mov    di,offset receive_dscps
  784.     call    segmoffs_to_phys
  785.     or    dx,cx            ;include the buffer size bits.
  786.     mov    init_receive[0],ax
  787.     mov    init_receive[2],dx
  788.  
  789.     mov    cx,TRANSMIT_BUF_COUNT
  790.     call    compute_log2
  791.  
  792.     mov    di,offset transmit_dscps
  793.     call    segmoffs_to_phys
  794.     or    dx,cx            ;include the buffer size bits.
  795.     mov    init_transmit[0],ax
  796.     mov    init_transmit[2],dx
  797.  
  798.     mov    di,offset init_block    ;now tell the board where the init
  799.     call    segmoffs_to_phys    ;  block is.
  800.  
  801.     push    dx
  802.     push    ax
  803.  
  804.     loadport
  805.     mov    ax,0            ;write the bus config register.
  806.     outport    CSR3
  807.  
  808.     pop    ax            ;write the low word.
  809.     outport    CSR1
  810.  
  811.     pop    ax            ;write the high word.
  812.     outport    CSR2
  813.  
  814.     mov    ax,0            ;non-promiscuous mode
  815.     call    initialize
  816.     jnc    init_ok
  817.  
  818.     mov    dx,offset bad_init_msg
  819.     mov    ah,9
  820.     int    21h
  821.  
  822.     stc
  823.     ret
  824.  
  825. init_ok:
  826. ;
  827. ; Now hook in our interrupt
  828. ;
  829.     call    set_recv_isr
  830.  
  831.     mov    dx,offset end_resident
  832.     clc
  833.     ret
  834.  
  835.     public    print_parameters
  836. print_parameters:
  837. ;echo our command-line parameters
  838.     mov    di,offset int_no
  839.     mov    dx,offset int_no_name
  840.     call    print_number
  841.     mov    di,offset io_addr
  842.     mov    dx,offset io_addr_name
  843.     call    print_number
  844.     ret
  845.  
  846. compute_log2:
  847. ;enter with cx = number of buffers.
  848. ;exit with cx = log2(number of buffers) << 13.
  849.     mov    ax,-1
  850. compute_log2_1:
  851.     inc    ax
  852.     shr    cx,1
  853.     jne    compute_log2_1
  854.     shl    ax,13
  855.     mov    cx,ax
  856.     ret
  857.  
  858.  
  859. segmoffs_to_phys:
  860. ;enter with es:di -> buffer.
  861. ;exit with dx:ax as the physical address of the buffer,
  862.  
  863.     mov    dx,es            ;get the high 4 bits of the segment,
  864.     shr    dx,16-4
  865.     mov    ax,es            ;and the low 12 bits of the segment.
  866.     shl    ax,4
  867.     add    ax,di            ;add in the offset.
  868.     adc    dx,0
  869.     ret
  870.  
  871.  
  872. detect_board:
  873. ;test to see if a board is located at io_addr.
  874. ;return nz if not.
  875.     loadport
  876.     setport    EBASE
  877.     in    al,dx            ;Check for Interlan's prefix word.
  878.     cmp    al,2
  879.     jne    detect_board_exit
  880.  
  881.     setport    EBASE+1
  882.     in    al,dx
  883.     cmp    al,7
  884.     jne    detect_board_exit
  885.  
  886.     setport    EBASE+EADDR_LEN        ;first byte following should be 0
  887.     in    al,dx
  888.     cmp    al,0
  889.     jne    detect_board_exit
  890.  
  891.     setport    EBASE+EADDR_LEN+1    ;second byte should be 55h
  892.     in    al,dx
  893.     cmp    al,55h
  894. detect_board_exit:
  895.     ret
  896.  
  897. code    ends
  898.  
  899.     end
  900.